home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
The Atari Compendium
/
The Atari Compendium (Toad Computers) (1994).iso
/
files
/
umich
/
network
/
ka9q
/
ka9q_src.arc
/
SLFP.C
< prev
next >
Wrap
C/C++ Source or Header
|
1988-12-02
|
12KB
|
523 lines
/* Send and receive IP datagrams on serial lines. Compatible with SL/FP
* as used with the Merit Network and MIT.
*/
#include <stdio.h>
#include "global.h"
#include "mbuf.h"
#include "iface.h"
#include "timer.h"
#include "ip.h"
#include "slfp.h"
#ifdef UNIX /* BSD or SYS5 */
#include "unix.h"
#else
# ifdef ATARI_ST
# include "st.h"
# else
# include "pc.h"
# include "asy.h"
# endif /* ATARI_ST */
#endif /* BSD or SYS5 */
#include "trace.h"
int asy_ioctl();
int slfp_send();
int doslfp();
int asy_output();
/* SL/FP level control structure */
struct slfp slfp[ASY_MAX];
char slfp_ack[ACK_LEN] = { SLFP_ACK } ;
char slfp_req[REQ_LEN] = { SLFP_REQ } ;
char ip_hdr[HDR_LEN] = { 2, 1, 0, 0 } ; /* IP Packet Header */
char ar_hdr[HDR_LEN] = { 2, 3, 0, 0 } ; /* "Addr Req" Packet Header */
struct interface asy_interface = /* Fake interface for "dump" proc */
{ NULLIF, "asy" } ; /* Name of "asy" interface */
/* Routine to Initialize the Async line for SL/FP processing.
* Mostly involves requesting the IP Address for this host.
*/
int
slfp_init(interface,pip_addr,modem_cmd)
struct interface *interface ;
int32 *pip_addr ; /* pointer to host ip address */
char *modem_cmd ; /* optional command to Modem */
{
register struct slfp *sp;
register struct timer *ar ;
char *modem_line ;
int i ;
sp = &slfp[interface->dev];
ar = &sp->ar_timer ;
sp->ar_pending = 1 ;
slfp[interface->dev].req_pending = 0 ;
/* If a Modem Command is present, send it and wait for Connection */
if (modem_cmd != NULLCHAR) {
char c; c='\r';
modem_line = (char *)malloc(strlen(modem_cmd)+2) ;
if (modem_line == NULLCHAR)
return -1 ;
strcpy(modem_line, modem_cmd);
strcat(modem_line, "\r") ;
asy_output(interface->dev,&c,1); /* Wake up modem */
set_timer(ar,500);
start_timer(ar);
while(ar->state == TIMER_RUN)
keep_things_going();
asy_output(interface->dev,modem_line,strlen(modem_line));
set_timer(ar, 30000) ; /* Wait upto 30 seconds for Connection */
} else
set_timer(ar, 500) ; /* Wait half a second before sending REQ's */
/* Request an IP Address upto 4 times (every 24 seconds) before giving up */
for (i=0; i<4; i++) {
start_timer(ar) ;
while (sp->ar_pending && (ar->state == TIMER_RUN)) {
keep_things_going() ; /* Can't return until timeout or addr */
if(kbread()==(-2)) /* Hit the Escape key */
return(-1);
}
if (!sp->ar_pending) {
if (modem_cmd != NULLCHAR)
free(modem_line) ;
return 0 ;
}
slfp_send(NULLBUF, interface, 0L, 0, 0, 0, 0) ;
set_timer(ar, 24000) ; /* Wait upto 24 seconds for IP Addr */
}
if (modem_cmd != NULLCHAR)
free(modem_line) ;
sp->ar_pending = 0 ;
return -1 ;
}
/* Send routine for point-to-point slfp
* This is a trivial function since slfp_encode adds the link-level header
*/
int
slfp_send(bp,interface,gateway,precedence,delay,throughput,reliability)
struct mbuf *bp; /* Buffer to send */
struct interface *interface; /* Pointer to interface control block */
int32 gateway;
char precedence;
char delay;
char throughput;
char reliability;
{
if(interface == NULLIF){
free_p(bp);
return;
}
dump(interface,IF_TRACE_OUT,TRACE_IP,bp);
(*interface->raw)(interface,bp);
}
/* Send a raw slfp frame -- also trivial */
slfp_raw(interface,bp)
struct interface *interface;
struct mbuf *bp;
{
/* Make "asy" interface a shadow of the SLFP interface */
asy_interface.trace = interface->trace ;
/* Queue a frame on the slfp output queue and start transmitter */
slfpq(interface->dev,bp);
}
/* Encode a raw packet in slfp framing, put on link output queue, and kick
* transmitter
*/
static
slfpq(dev,bp)
int16 dev; /* Serial line number */
struct mbuf *bp; /* Buffer to be sent */
{
register struct slfp *sp;
struct mbuf *slfp_encode();
if((bp = slfp_encode(dev,bp)) == NULLBUF)
return;
sp = &slfp[dev];
enqueue(&sp->sndq,bp);
dump(&asy_interface,IF_TRACE_OUT,TRACE_SLFP,bp);
sp->sndcnt++;
if(sp->tbp == NULLBUF)
slfp_asy_start(dev);
}
/* Handle REQ-ACK Timer expiration
*/
void
slfp_req_notify(dev)
int16 dev;
{
register struct slfp *sp;
register struct timer *rt ; /* Timer for REQ-ACK negotiation */
struct mbuf *bp ;
sp = &slfp[dev];
rt = &(sp->req_timer) ;
if (sp->reqcnt++ >= 10) {
sp->tbp = NULLBUF ;
sp->req_pending = 0 ;
bp = dequeue(&sp->sndq);
sp->sndcnt--;
free_p(bp) ;
}
else {
set_timer(rt,2000) ; /* 2-Second Timeout for ACK */
start_timer(rt) ;
asy_output(dev, slfp_req, REQ_LEN) ;
}
}
/* Start output, if possible, on asynch device dev */
static
slfp_asy_start(dev)
int16 dev;
{
register struct slfp *sp;
register struct timer *rt ; /* Timer for REQ-ACK negotiation */
struct mbuf *bp ;
if(!stxrdy(dev))
return; /* Transmitter not ready */
sp = &slfp[dev];
bp = sp->tbp ;
if(bp != NULLBUF){
/* transmission just completed */
free_p(bp) ;
sp->tbp = NULLBUF;
}
if(sp->sndq == NULLBUF)
return; /* No work */
rt = &(sp->req_timer) ;
if (sp->req_pending)
return ;
sp->reqcnt = 0 ;
sp->req_pending = 1 ;
rt->func = slfp_req_notify ;
rt->arg = (char *)dev ;
set_timer(rt,2000) ; /* 2-Second Timeout for ACK */
start_timer(rt) ;
asy_output(dev, slfp_req, REQ_LEN) ;
}
/* Encode a packet in SL/FP format */
static
struct mbuf *
slfp_encode(dev,bp)
int16 dev; /* Serial line number */
struct mbuf *bp;
{
struct mbuf *lbp; /* Mbuf containing line-ready packet */
register char *cp;
char c;
/* Allocate output mbuf that's twice as long as the packet.
* This is a worst-case guess (consider a packet full of SLFP_ENDs!)
*/
lbp = alloc_mbuf(HDR_LEN + 2*len_mbuf(bp) + 2);
if(lbp == NULLBUF){
/* No space; drop */
free_p(bp);
return NULLBUF;
}
cp = lbp->data;
/* Prefix packet with the Correct Link-Level Header */
if (slfp[dev].ar_pending)
memcpy(cp, ar_hdr, HDR_LEN) ;
else
memcpy(cp, ip_hdr, HDR_LEN) ;
cp += HDR_LEN ;
/* Copy input to output, escaping special characters */
while(pullup(&bp,&c,1) == 1){
switch(c & 0xff){
case SLFP_ESC:
*cp++ = SLFP_ESC;
*cp++ = SLFP_ESC - SLFP_ESC;
break;
case SLFP_END:
*cp++ = SLFP_ESC;
*cp++ = SLFP_END - SLFP_ESC;
break;
case SLFP_ACK:
*cp++ = SLFP_ESC;
*cp++ = SLFP_ACK - SLFP_ESC;
break;
case SLFP_REQ:
*cp++ = SLFP_ESC;
*cp++ = SLFP_REQ - SLFP_ESC;
break;
default:
*cp++ = c;
}
}
*cp++ = SLFP_END;
lbp->cnt = cp - lbp->data;
return lbp;
}
#ifdef MSDOS
/* Invoked when SLFP_REQ is received during xmit of outgoing packet.
* This allows immediate reception of packet from SCP, rather than
* forcing it to buffer it until we finish sending the outgoing packet
*/
static
unsigned
slfp_urgent(dev)
int16 dev; /* SL/FP unit number */
{
register struct dma *dp ;
dp = &asy[dev].dma ;
if (dp->last_octet == SLFP_ESC)
return 256 ;
else {
asy[dev].urgent = NULLCHAR ;
return SLFP_ACK ;
}
}
#endif
void
hndl_rcvd_req(dev, sp)
int16 dev; /* SL/FP unit number */
register struct slfp *sp;
{
char i_state ;
if (sp->reqd) { /* REQ before rcv'g END of last Packet! */
sp->missed_ends++ ;
free_p(sp->rbp); /* throw away current packet */
sp->rbp = NULLBUF;
sp->rcnt = 0;
}
sp->reqd = 1 ;
i_state = disable() ;
#ifdef MSDOS
if (asy[dev].dma.flags)
asy[dev].urgent = slfp_urgent ;
else
#endif
asy_output(dev, slfp_ack, ACK_LEN) ;
restore(i_state) ;
}
void
hndl_rcvd_ack(dev, sp)
int16 dev; /* SL/FP unit number */
register struct slfp *sp;
{
char i_state ;
i_state = disable() ;
if (sp->req_pending == 0) {
sp->false_acks++ ;
restore(i_state) ;
return ;
}
sp->req_pending = 0 ;
stop_timer(&(sp->req_timer)) ;
restore(i_state) ;
sp->tbp = dequeue(&sp->sndq);
sp->sndcnt--;
asy_output(dev,sp->tbp->data,sp->tbp->cnt);
}
/* Process incoming bytes in